const { stdout_columns } = require("../commands/share_data");
const { json_compacted, formatTimestampMillisec } = require("./transform_tool");
require("colors");

const colors = [
    "gray",
    "reset",
    "cyan",
    "green",
    "yellow",
    "red",
    "red",
    "magenta",
];

const LogLevel = {
    NONE: -1,
    WHISPER: 0,
    DEBUG: 1,
    INFO: 2,
    SUCCESS: 3,
    WARNING: 4,
    ERROR: 5,
    VITAL: 6,
    SYSTEM: 7,
    STDOUT: 99,
};

function log(msg, end = "\n", level = -1, force = true, with_date = false) {
    if (!checkStdOut(level)) {
        return;
    }
    if (logLevel > level && !force) {
        return;
    }
    if (typeof msg === "object" && !msg) {
        msg = "<空>";
        level = LogLevel.SYSTEM;
    }
    if (with_date) {
        msg = `[${formatTimestampMillisec(Date.now())}] ${msg}`;
    }
    // clearLine();
    const color = colors[level];
    if (color && ""[color]) {
        process.stdout.write(msg.toString()[color] + end);
    } else {
        process.stdout.write(msg.toString() + end);
    }
}

function log2(msg, end = "\n", level = -1, with_date = false) {
    if (typeof msg === "object" && !msg) {
        msg = "<空>";
        level = LogLevel.SYSTEM;
    }
    if (with_date) {
        msg = `[${formatTimestampMillisec(Date.now())}] ${msg}`;
    }
    // clearLine();
    const color = colors[level];
    if (color) {
        process.stdout.write(msg.toString()[color] + end);
    } else {
        process.stdout.write(msg.toString() + end);
    }
}

function write(msg) {
    log(msg.toString(), "", -1, true);
}

function debug(msg, end = "\n", force = false, with_date = false) {
    log(msg.toString(), end, LogLevel.DEBUG, force, with_date);
}

function info(msg, end = "\n", force = false, with_date = false) {
    log(msg.toString(), end, LogLevel.INFO, force, with_date);
}

function success(msg, end = "\n", force = false, with_date = false) {
    log(msg.toString(), end, LogLevel.SUCCESS, force, with_date);
}

function warn(msg, end = "\n", force = false, with_date = false) {
    log(msg.toString(), end, LogLevel.WARNING, force, with_date);
}

function error(msg, end = "\n", force = false) {
    log(msg.toString(), end, LogLevel.ERROR, force);
}

function error2(msg, end = "\n") {
    log2(msg.toString(), end, LogLevel.ERROR);
}

function whisper(msg, end = "\n", force = false, with_date = false) {
    log(msg.toString(), end, LogLevel.WHISPER, force, with_date);
}

function stdout(msg) {
    process.stdout.write(msg.toString());
}

function omit(
    msg,
    max_num = stdout_columns - 5,
    prefix_num = stdout_columns - 5,
    suffix_num = 0,
    omit_chars = " ... ",
) {
    if (msg && msg.length > max_num) {
        return `${msg.substr(0, prefix_num)}${omit_chars}${msg.substr(msg.length - suffix_num)}`;
    } else {
        return msg;
    }
}

function omit_offset(msg, offset) {
    return omit(
        msg,
        stdout_columns - offset - 5,
        stdout_columns - offset - 5,
        0,
        " ... ",
    );
}

function getPrint(value, no_omit = false) {
    if (Array.isArray(value)) {
        return `Array[${value.length}]${!no_omit ? omit(json_compacted(value, 2)) : json_compacted(value, 2)}`;
    } else {
        value =
            typeof value === "string" ? `"${value}"` : json_compacted(value, 2);
        return !no_omit ? omit(value) : value;
    }
}

let lastError = null;
let lastErrorCode = 0;

let logLevel = 0;

function getLastError() {
    return lastError;
}

function getLastErrorCode() {
    return lastErrorCode;
}

function setLastError(err, code) {
    lastError = err;
    lastErrorCode = code;
}

function resetError(extraError) {
    if (lastError) {
        if (typeof extraError === "string") {
            error(`${lastError} [${extraError}]`);
        } else {
            error(`${lastError}`);
        }
    }
    lastError = null;
    lastErrorCode = null;
}

let lastCommand = null;
let lastCommandFormated = 0;
function setLastCommand(raw, formated) {
    lastCommand = raw;
    lastCommandFormated = formated;
}

function getLastCommand() {
    return [lastCommand, lastCommandFormated];
}

let lastExecFile = null;
function setLastExecFile(file) {
    lastExecFile = file;
}

function getLastExecFile() {
    return lastExecFile;
}

function setLogLevel(level) {
    logLevel = level;
}

function isStdOut() {
    return logLevel === LogLevel.STDOUT;
}

function checkStdOut(level) {
    return logLevel !== LogLevel.STDOUT || logLevel === level;
}

module.exports = {
    getLastError,
    getLastErrorCode,
    setLastError,
    resetError,
    omit,
    log,
    debug,
    info,
    warn,
    error,
    error2,
    whisper,
    stdout,
    getPrint,
    success,
    isStdOut,
    checkStdOut,
    write,
    omit_offset,
    setLogLevel,
    LogLevel,
    setLastCommand,
    getLastCommand,
    setLastExecFile,
    getLastExecFile,
};
